#include "QtMqtt.h"
#include "global.h"

QtMqtt::QtMqtt(QObject *parent)
    : QObject{parent}
{
    MqttHost = "47.100.21.145";
    MqttPort = "1883";
    MqttUserName = "emqx@lightrim.cn";
    MqttPassword = "lightRimCn2019";
    MqttServerTopic = "LrServerData";
    MqttProcessTopic = "LrServerDataProcess";
    MqttClientTopic = "LrClientData";
    MqttAppCloudTopic = "AppCloudData";
}

void QtMqtt::fnMqttClosed(){
    if (mqttClient) {
        if (mqttClient->isConnectedToHost()) {
            mqttClient->disconnectFromHost();
        }
        mqttClient->deleteLater();
    }
    this->deleteLater();
}

/**
 * @brief QtMqtt::fnMqttConnectStart
 * 连接服务器
 */
void QtMqtt::fnMqttConnectStart(){
    // qDebug() << "fnMqttConnectStart" << __LINE__ << QThread::currentThreadId();
    if (QThread::currentThread() != this->thread()) {
        QMetaObject::invokeMethod(this, "fnMqttConnectStart",
                                  Qt::QueuedConnection);
        return;
    }
    QNetworkConfigurationManager mgr;
    connect(&mgr, &QNetworkConfigurationManager::onlineStateChanged, this, [&](bool isOnline){
        QString netStatus = isOnline?"正常":"断开";
        QString strContent = QString("%1 [Line%2] : 检测到网络连接%3").arg(__FUNCTION__).arg(__LINE__).arg(netStatus);
        Global::fnSaveOperation(strContent);

        if(isOnline)
            this->fnConnectToHost(true);
    });

    if(!mgr.isOnline()){
        QString strContent = QString("%1 [Line%2] : 检测到当前无可用的网络连接").arg(__FUNCTION__).arg(__LINE__);
        Global::fnSaveOperation(strContent);
        QStringList param;
        param.push_back("ShowMessages");
        param.push_back("3");
        param.push_back("网络不通，远程服务将受影响！");
        emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
        param.clear();
        return;
    }
    this->fnConnectToHost(true);
}

void QtMqtt::fnConnectToHost(bool isFirst){
    if (QThread::currentThread() != this->thread()) {
        QMetaObject::invokeMethod(this, "fnConnectToHost",
                                  Qt::QueuedConnection,
                                  Q_ARG(bool, isFirst));
        return;
    }
    if(isFirst){
        QString strContent = QString("%1 [Line%2] : 正在连接MQTT服务").arg(__FUNCTION__).arg(__LINE__);
        Global::fnSaveOperation(strContent);
    }

    if (mqttClient && mqttClient->isConnectedToHost())
        return;

    if(Global::appDeviceNumber == ""){
        QString strContent = QString("%1 [Line%2] : 连接MQTT服务被终止：应用ID为空字串").arg(__FUNCTION__).arg(__LINE__);
        Global::fnSaveOperation(strContent);
        QStringList param;
        param.push_back("ShowMessages");
        param.push_back("4");
        param.push_back("应用ID为空。远程服务连接被终止！");
        emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
        param.clear();
        return;
    }

    if(!mqttClient){
        mqttClient = new Client();
        mqttClient->setParent(this);
        mqttClient->moveToThread(thread());
        connect(mqttClient, SIGNAL(connected()),
                this, SLOT(onMqttConnected()), Qt::QueuedConnection);
        connect(mqttClient, SIGNAL(disconnected()),
                this, SLOT(onMqttConnected()), Qt::QueuedConnection);
        connect(mqttClient, &QMQTT::Client::subscribed,
                this, &QtMqtt::onMqttSubscribed, Qt::QueuedConnection);
        connect(mqttClient, &QMQTT::Client::received,
                this, &QtMqtt::onMqttReceived, Qt::QueuedConnection);

        connect(MGlobal::fnGetInstance(), &MGlobal::CallInsidePageAction,
                this, &QtMqtt::fnExecuFunction);
    };

    // 设置 MQTT 参数
    mqttClient->setClientId(Global::appDeviceNumber);  //客户端ID不能重复
    mqttClient->setHostName(MqttHost);
    mqttClient->setPort(static_cast<quint16>(MqttPort.toUInt()));
    mqttClient->setUsername(MqttUserName);
    mqttClient->setPassword(MqttPassword.toLocal8Bit());
    mqttClient->setKeepAlive(60);
    mqttClient->setCleanSession(false);
    mqttClient->setAutoReconnect(true);
    mqttClient->setAutoReconnectInterval(60);

    // 连接服务器
    mqttClient->connectToHost();
}

/**
 * @brief QtMqtt::onMqttConnected
 * 连接成功的操作
 */
void QtMqtt::onMqttConnected(){
    if(!mqttClient)
        return;
    QString msg = !mqttClient->isConnectedToHost() ? "MQTT服务未连接或被断开" : "MQTT服务连接成功";
    QString strContent = QString("%1 [Line%2] : %3").arg(__FUNCTION__).arg(__LINE__).arg(msg);
    Global::fnSaveOperation(strContent);

    // 订阅本机消息
    if(mqttClient->isConnectedToHost()){
        QString tiTopic = QString("%1/%2/%3/#").arg(MqttClientTopic,Global::appClientID,Global::appDeviceNumber);
        mqttClient->subscribe(tiTopic, 1);
        Global::fnExecSleep(200);

        tiTopic = QString("%1/%2/%3/#").arg(MqttAppCloudTopic,Global::appClientID,Global::appDeviceNumber);
        mqttClient->subscribe(tiTopic, 1);
    }
}

/**
 * @brief QtMqtt::fnMqttSubscribe
 * @param topic
 * @param qos
 * 订阅主题
 */
void QtMqtt::fnMqttSubscribe(QString topic, int qos){
    if(!mqttClient)
        return;
    if(topic == "" || !mqttClient->isConnectedToHost())
        return;
    quint8 qost = static_cast<quint8>(qos);
    mqttClient->subscribe(QString("%1/%2/#").arg(MqttAppCloudTopic,topic), qost);
}

/**
 * @brief QtMqtt::onMqttSubscribed
 * @param topic
 * @param qos
 * 订阅主题成功的操作
 */
void QtMqtt::onMqttSubscribed(const QString& topic, const quint8 qos){
    Q_UNUSED(topic)
    Q_UNUSED(qos)
}

/**
 * @brief QtMqtt::onMqttUnsubscribed
 * @param topic
 * 取消订阅主题
 */
void QtMqtt::onMqttUnsubscribed(const QString& topic){
    if(!mqttClient)
        return;
    mqttClient->unsubscribe(QString("%1/%2/#").arg(MqttAppCloudTopic,topic));
    //qDebug() << __func__ << __LINE__ << "取消订阅" << topic;
}

/**
 * @brief QtMqtt::fnSendMessage
 * @param optParameter
 * 发送MQTT消息//游客操作将被终止
 */
void QtMqtt::fnSendMqttMessage(QString optParameter){
    QJsonObject usrInfo = Global::usrLoggedInfo;
    if(usrInfo.isEmpty()){
        QStringList param;
        param.push_back("ShowMessages");
        param.push_back("3");
        param.push_back("未登录，或登录已超时！");
        emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
        param.clear();
        return;
    }
    if(!Global::lstAuthority.contains(Global::strAuthority)){
        QStringList param;
        param.push_back("ShowMessages");
        param.push_back("4");
        param.push_back("权限不足，操作终止！");
        emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
        param.clear();
        return;
    }
    QJsonDocument doc = QJsonDocument::fromJson(optParameter.toUtf8());
    if(doc.isNull() || !doc.isObject()){
        QStringList param;
        param.push_back("ShowMessages");
        param.push_back("3");
        param.push_back("参数传输失败或格式不正确！");
        emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
        param.clear();
        return;
    }
    QJsonObject dataObject = doc.object();
    QString idMqttMessage = dataObject.value("idMqttMessage").toString();
    if(mqttClient && !mqttClient->isConnectedToHost() && !idMqttMessage.isEmpty()){
        QStringList param = {"MqttPublished",
                             "Failure",
                             "远程服务未连接或已断开！",
                             idMqttMessage};
        emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
        param.clear();
        return;
    }

    QJsonObject sendData = dataObject.value("sendData").toObject();
    float version = dataObject.value("version").toString().leftRef(3).toFloat();
    if(sendData.value("MsgType").toString() == "APPUPDATA"){
        QJsonObject data = Global::devDataCache.value("RealData");
        version = data.value("VersionName").toString().leftRef(3).toFloat();
        QString devNumber1 = dataObject.value("topic").toString().split("/").last(),
            txtNumber = version < 2.0 ? "DeviceNumber" : "devNumber",
            devNumber2 = data.value(txtNumber).toString();

        if(devNumber2 == ""){
            QStringList param = {"MqttPublished",
                                 "Failure",
                                 "远程数据为空，请确认设备是否离线！",
                                 idMqttMessage};
            emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
            param.clear();
            return;
        }

        if(devNumber1 != devNumber2){
            QString msg = QString("与订阅的设备数据不匹配！\n%1 && %2").arg(devNumber1.right(6),devNumber2.right(6));
            QStringList param = {"MqttPublished",
                                 "Failure",
                                 msg,
                                 idMqttMessage};
            emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
            param.clear();
            return;
        }
    }


    QString topic =  MqttClientTopic + dataObject.value("topic").toString();
    quint8 qos = dataObject.value("qos").toString().toUInt();
    QByteArray arrSendMqttData = QJsonDocument(sendData).toJson(QJsonDocument::Compact).simplified();
    const quint16 id         = idMqttMessage.toUInt();
    const QString pubTopic   = topic;
    const QByteArray payload = arrSendMqttData;
    const quint8 pubQos         = qos;       //质量
    const bool retain        = false;   //留言
    const Message message(id, pubTopic, payload, pubQos, retain);
    if(mqttClient)
        mqttClient->publish(message);

    if(version < 2.0 || idMqttMessage == "noWaiting"){
        QString msgTye = sendData.value("MsgType").toString();
        if(msgTye == "APPUPDATA" || msgTye == "BLACKLIST"){
            QString msg = "信息已送出，请核实返馈结果！";
            QStringList param = {"MqttPublished",
                                 "Success", msg, idMqttMessage};
            emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
            param.clear();
        }
        return;
    }
    // 等待设备端返回(v2.0+)
    if(itReturnResponse != -1)
        itReturnResponse = -1;

    QEventLoop eventloop;
    QTimer checkTimer;
    checkTimer.setInterval(1500);
    int cntTimeout = 0;
    QEventLoop::connect(&checkTimer, &QTimer::timeout, this, [&]() {
        cntTimeout += 1;
        if (itReturnResponse != -1 || cntTimeout == 3){
            checkTimer.stop();
            eventloop.quit();
        }
    });
    checkTimer.start();
    eventloop.exec();
    if(cntTimeout >= 3){
        checkTimer.stop();
        eventloop.quit();
        QString msg = "信息已送出，但远程响应超时。\n请自行核实返馈结果！";
        QStringList param = {"MqttPublished",
                             "Success", msg, idMqttMessage};
        emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
        param.clear();
        return;
    }

    if(cntTimeout > 0)
        cntTimeout = 0;
    if(itReturnResponse == -1)
        return;

    QString msg = "";
    if(itReturnResponse == 2)
        msg = "远程已响应请求，且完成操作。\n请核实返馈结果！";
    if(itReturnResponse == 1)
        msg = "远程已响应请求，但可能没有执行。\n请尝试重启或升级远程系统！";
    if(itReturnResponse == 0)
        msg = "远程已拒接响应，\n您的操作密码不正确！";

    QStringList param = {"MqttPublished",
                         "Success", msg, idMqttMessage};
    emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
    // qDebug() << param;
    param.clear();
    itReturnResponse = -1;
}

/**
 * @brief QtMqtt::onMqttReceived
 * @param message
 * 接收到消息
 */
void QtMqtt::onMqttReceived(const QMQTT::Message& message){
    QString tMessageStr = message.payload();
    QByteArray tMessage = tMessageStr.toUtf8().simplified().replace("$","\"");
    tMessage = tMessage.replace("^"," ");
    QJsonParseError err_rpt;
    QJsonDocument docMessage = QJsonDocument::fromJson(tMessage, &err_rpt);
    if(err_rpt.error != QJsonParseError::NoError){
        //qDebug() << __FUNCTION__ << __LINE__ << "QMQTT::Message::Error" << err_rpt.error;
        return;
    }
    QJsonObject jsonMessage = docMessage.object();
    QString msgType = jsonMessage.value("MsgType").toString();

    if(msgType == "UPDATABACK"){
        // 2.0等待远控响应结果
        QJsonObject mqttData = jsonMessage.value("MqttData").toObject();
        itReturnResponse = mqttData.value("Step").toString().toInt();
        if(itReturnResponse == 1 && mqttData.value("Result").toString() != "OK")
            itReturnResponse = 0;
        return;
    }
    if(msgType == "RETURNOPERATIONRECORD" || msgType == "CHECKUPGRADEBACK" || msgType == "BINDBACK"){
        //用记操作记录//检查新版本返回结果//绑定请求响应
        QStringList param;
        param.push_back("response");
        param.push_back(QString(QJsonDocument(jsonMessage).toJson(QJsonDocument::Compact)));
        param.push_back(msgType);
        emit MGlobal::fnGetInstance()->CallInsidePageAction(param);
        param.clear();
        return;
    }
    if(msgType == "UnbindDeviceUser"){
        //被用户删除绑定
        // QJsonObject mqttData = jsonMessage.value("MqttData").toObject();
        // int uid = mqttData.value("iptAddr").toInt();
        // if(uid == Global::usrLoggedInfo.value("uid").toString().toInt()){
        //     QString devNumber = mqttData.value("iptValue").toString();
        //     if(Global::CurrDevNumber == devNumber){
        //         //关闭当前页
        //         //emit callInsidePage(QStringList(msgType));
        //     }
        //     QJsonObject result;
        //     //取消订阅
        //     for(int i = 0;i < Global::usrBindDevices.size(); i++){
        //         result = Global::usrBindDevices.at(i).toObject();
        //         if(devNumber == result.value("devDeviceNumber").toString()){
        //             QString clientID= result.value("devClientID").toString();
        //             QString clientTopic = QString("%1/%2").arg(clientID, devNumber);
        //             this->onMqttUnsubscribed(clientTopic);
        //             break;
        //         }
        //     }
        // }
        return;
    }

    if(msgType == "PSDATA"){
        // 缓存单台设备的实时数据
        QJsonObject mqttData = jsonMessage.value("MqttData").toObject();
        float version = mqttData.value("VersionName").toString().leftRef(3).toFloat();
        QString devNumber = version >= 2.0
                                ? mqttData.value("devNumber").toString()
                                : mqttData.value("DeviceNumber").toString();
        if(Global::CurrDevNumber != "" && devNumber == Global::CurrDevNumber)
            Global::devDataCache.insert("RealData", mqttData);
        else if(devNumber == Global::CarouselDevNumber)
            Global::devDataCache.insert("CarouselData", mqttData);
        // 获取当前本地时间的时间戳（秒）
        Global::devDataListTime = QDateTime::currentDateTime().toSecsSinceEpoch();
    }
}

void QtMqtt::fnExecuFunction(QStringList optParameter){
    if(optParameter.last() == "MqttSubscribe" && optParameter.size() > 1){
        this->fnMqttSubscribe(optParameter.at(0), optParameter.at(1).toInt());
        return;
    }
    if(optParameter.last() == "MqttUnsubscribed"){
        this->onMqttUnsubscribed(optParameter.first());
        return;
    }
    if(optParameter.last() == "SendMqttMessage"){
        optParameter.removeLast();
        this->fnSendMqttMessage(optParameter.first());
        return;
    }
}
